package com.flyqiu.form.core.rule;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.flyqiu.common.tools.FlyQiuCollectionTools;
import com.flyqiu.form.api.rule.FlyQiuDataPropValidate;
import com.flyqiu.form.api.rule.FlyQiuDataRuleManage;
import com.flyqiu.form.api.rule.FlyQiuFormDataRule;
import com.flyqiu.form.api.tools.FlyQiuAvueColTools;
import com.flyqiu.form.api.tools.FlyQiuTableOptionTools;
import com.flyqiu.form.common.enums.FlyQiuFormDataAction;
import com.flyqiu.form.core.rule.valid.MinFlyQiuFormDataRule;
import com.flyqiu.form.core.rule.valid.RequiredFlyQiuFormDataRule;
import com.flyqiu.form.model.entity.FlyQiuTableConfig;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

public class DefaultFlyQiuDataRuleManage implements FlyQiuDataRuleManage {
    private final Map<String, FlyQiuFormDataRule> dataRules = new HashMap<>();


    public DefaultFlyQiuDataRuleManage() {
        dataRules.put(RequiredFlyQiuFormDataRule.KEY, new RequiredFlyQiuFormDataRule());
        dataRules.put(MinFlyQiuFormDataRule.KEY, new MinFlyQiuFormDataRule());
    }

    @Override
    public void registerDataRule(FlyQiuFormDataRule rule) {
        dataRules.put(rule.getValue(), rule);
    }

    @Override
    public FlyQiuFormDataRule unregisterDataRule(String ruleValueKey) {
        return dataRules.remove(ruleValueKey);
    }

    @Override
    public void validateForm(FlyQiuTableConfig config, JSONObject formData, FlyQiuFormDataAction dataAction) {
        JSONArray columns = FlyQiuTableOptionTools.getColumns(config.getFormOption());
        if (FlyQiuCollectionTools.isEmpty(columns)) {
            return;
        }
        JSONObject column;
        String prop;
        FlyQiuTableConfig dynamicFormConfig;
        List<FlyQiuDataPropValidate> dataValidates;
        for (int i = 0; i < columns.size(); i++) {
            column = columns.getJSONObject(i);
            dataValidates = getColumnRules(column);
            prop = FlyQiuAvueColTools.getColumnProp(column);
            if (FlyQiuAvueColTools.isDynamic(column)) {
                dynamicFormConfig = FlyQiuAvueColTools.getAvueDynamicFormConfig(config, column);
                validateListData(dynamicFormConfig, formData.getJSONArray(prop), dataAction);
            }
            for (FlyQiuDataPropValidate validate : dataValidates) {
                validate.dataValidate(config, formData, formData.get(prop), dataAction);
            }
        }
    }


    private List<FlyQiuDataPropValidate> getColumnRules(JSONObject column) {
        List<FlyQiuDataPropValidate> result = new ArrayList<>();
        JSONArray rules = FlyQiuAvueColTools.getColumnRules(column);
        if (FlyQiuCollectionTools.isEmpty(rules)) {
            return result;
        }
        for (int i = 0; i < rules.size(); i++) {
            JSONObject rule = rules.getJSONObject(i);
            List<FlyQiuDataPropValidate> dataValidates = ruleConvertDataValidate(column, rule);
            result.addAll(dataValidates);
        }

        return result;
    }

    private List<FlyQiuDataPropValidate> ruleConvertDataValidate(JSONObject column, JSONObject rule) {
        Set<String> keySet = rule.keySet();
        List<FlyQiuDataPropValidate> result = new ArrayList<>();
        for (String key : keySet) {
            FlyQiuFormDataRule flyQiuFormDataRule = dataRules.get(key);
            if (flyQiuFormDataRule == null) continue;
            FlyQiuDataPropValidate match = flyQiuFormDataRule.createDataValidate(column, rule);
            if (match != null) {
                result.add(match);
            }
        }
        result = result.stream().sorted(Comparator.comparingInt(FlyQiuDataPropValidate::getSort)).toList();
        return result;
    }


    @Override
    public void validateListData(FlyQiuTableConfig config, JSONArray dataSource, FlyQiuFormDataAction dataAction) {
        DefaultRuleValidateContext context = new DefaultRuleValidateContext();
        context.setTableConfig(config);
        valid(context, dataSource, dataAction);

    }

    private void valid(DefaultRuleValidateContext context, JSONArray dataSource, FlyQiuFormDataAction dataAction) {
        if (FlyQiuCollectionTools.isEmpty(dataSource)) {
            return;
        }
        FlyQiuTableConfig qiuTableConfig = context.getTableConfig();
        JSONArray columns = FlyQiuTableOptionTools.getColumns(qiuTableConfig.getFormOption());
        if (FlyQiuCollectionTools.isEmpty(columns)) {
            return;
        }
        Map<JSONObject, List<FlyQiuDataPropValidate>> rulesMap = new LinkedHashMap<>();
        JSONObject column;
        String prop;
        List<FlyQiuDataPropValidate> columnRules;
        for (int i = 0; i < columns.size(); i++) {
            column = columns.getJSONObject(i);
            prop = FlyQiuAvueColTools.getColumnProp(column);
            if (StringUtils.isBlank(prop)) {
                continue;
            }
            columnRules = getColumnRules(column);
            if (FlyQiuCollectionTools.isEmpty(columnRules)) {
                continue;
            }
            rulesMap.put(column, columnRules);

        }
        if (FlyQiuCollectionTools.isEmpty(rulesMap)) {
            return;
        }

        context.setDataSource(dataSource);


        Set<Map.Entry<JSONObject, List<FlyQiuDataPropValidate>>> entries = rulesMap.entrySet();
        FlyQiuTableConfig dynamicFormConfig;
        JSONObject rowData;

        DefaultRuleValidateContext dynamicContext;
        for (int i = 0; i < dataSource.size(); i++) {
            rowData = dataSource.getJSONObject(i);
            context.setRow(rowData);
            context.setRowIndex(i);
            for (Map.Entry<JSONObject, List<FlyQiuDataPropValidate>> colRules : entries) {

                column = colRules.getKey();
                context.setCol(column);
                columnRules = colRules.getValue();
                prop = FlyQiuAvueColTools.getColumnProp(column);
                if (FlyQiuAvueColTools.isDynamic(column)) {
                    dynamicFormConfig = FlyQiuAvueColTools.getAvueDynamicFormConfig(qiuTableConfig, column);
                    dynamicContext = new DefaultRuleValidateContext();
                    dynamicContext.setTableConfig(dynamicFormConfig);
                    valid(dynamicContext, rowData.getJSONArray(prop), dataAction);
                }

                for (FlyQiuDataPropValidate validate : columnRules) {
                    validate.dataValidate(context, rowData.get(prop), dataAction);
                }
            }

        }

    }
}
